package it.unibo.deis.lia.mmhc.fnm;

//trova ip dei miei figli e dei miei padri quindi dei miei vicini
import java.io.BufferedReader;
import java.io.FileReader;

import java.io.InputStreamReader;

import java.util.Calendar;
import java.util.TimeZone;
import java.util.Vector;

import it.unibo.deis.lia.mmhc.com.ConnectorManager;
import it.unibo.deis.lia.mmhc.nip.NetworkInterfaceProvider;

import it.unibo.deis.lia.mmhc.rom.RoutingManager;
import it.unibo.deis.lia.mmhc.util.Channel;

import it.unibo.deis.lia.networkInterface.Bluetooth;
import it.unibo.deis.lia.networkInterface.GenericNetworkInterface;
import it.unibo.deis.lia.networkInterface.IEEE80211;

public class FindNeighbours extends Thread {

	private static final String LEASEFILE_PATH = "/var/lib/dhcp3/";
	// private static final String LEASEFILE_PATH = "/var/db/";//mio db dhcpd

	private NetworkInterfaceProvider nip;
	private ConnectorManager com;
	private Vector<String> neighbourgs;
	private RoutingManager rom;
	private boolean go = true;
	private static FindNeighbours findNeighbours = null;

	public synchronized static FindNeighbours getInstance() {
		if (findNeighbours == null) {
			try {
				findNeighbours = new FindNeighbours();
				// findNeighbours.start();
			} catch (Exception e) {
				System.err.println("Impossibile creare il findManager");
				e.printStackTrace();
			}
		}
		return findNeighbours;
	}

	public FindNeighbours() {
		try {
			this.nip = NetworkInterfaceProvider.getInstance();
			this.com = ConnectorManager.getInstance();
			this.neighbourgs = new Vector<String>();
			this.rom = RoutingManager.getInstance();
		} catch (Exception e) {
			System.err.println("Impossibile creare il FindNeighbours");
		}
	}

	protected Vector<String> getChilds() {
		try {
			Vector<String> myChilds = new Vector<String>();
			Vector<GenericNetworkInterface> myInterfaces = new Vector<GenericNetworkInterface>();
			myInterfaces = nip.getAvailableInterfaces();
			Vector<String> myHddAdd = new Vector<String>();
			for (int i = 0; i < myInterfaces.size(); i++) {
				myHddAdd.add(myInterfaces.elementAt(i).getHardwareAddress());
			}

			boolean trueChild = false;
			BufferedReader leases = null;
			if (System.getProperty("os.name").startsWith("Linux")) {
				leases = new BufferedReader(new FileReader(LEASEFILE_PATH
						+ "dhcpd.leases"));
			} else {
				throw new Exception("Not supported Operating System");
			}
			String line = leases.readLine();
			while (line != null) {
				if (!line.startsWith("#") && line.contains("lease")) {
					String tokens[] = line.split("[ {]");

					// System.out.println("\t\tactiveClients remoteOctects "+tokens[1]);
					String child = tokens[1];
					// String childOctects[]=tokens[1].split("[.]");

					do {
						line = leases.readLine();
					} while (line != null && !line.contains("ends"));
					tokens = line.split("[ :;/]");
					int sec = Integer.parseInt(tokens[tokens.length - 1]);
					int min = Integer.parseInt(tokens[tokens.length - 2]);
					int hour = Integer.parseInt(tokens[tokens.length - 3]);
					int day = Integer.parseInt(tokens[tokens.length - 4]);
					int month = Integer.parseInt(tokens[tokens.length - 5]);
					int year = Integer.parseInt(tokens[tokens.length - 6]);
					// System.out.println("\t\tactiveClients "+year+" "+(month-1)+" "+day+" "+hour+" "+min+" "+sec);
					Calendar time = Calendar.getInstance();
					time.setTimeZone(TimeZone.getTimeZone("UTC"));
					time.set(year, (month - 1), day, hour, min, sec);
					trueChild = false;
					if (time.getTimeInMillis() > System.currentTimeMillis()) {
						trueChild = true;
					}
					if (trueChild) {
						do {
							line = leases.readLine();
						} while (line != null && !line.contains("hardware"));
						tokens = line.split("[ ;]");
						String hdrAddNoDotted = tokens[tokens.length - 1];// .split("[:]");
						// String hdrAdd="";
						// for(int i=0;i<hdrAddNoDotted.length;i++){
						// hdrAdd+=hdrAddNoDotted[i];
						// }
						// System.out.println(hdrAdd);
						if (vectorContains(myHddAdd, hdrAddNoDotted)) {
							trueChild = false;
						}
						if (trueChild) {
							// sarebbe il caso di fare un ping per vedere se la
							// connessione è veramente attiva

							if (!vectorContains(myChilds, child)
									&& activeIP(child))
								myChilds.add(child);

						}
					}

				}

				line = leases.readLine();
			}
			return myChilds;
		} catch (Exception e) {
			System.err.println("Impossibile trovare i figli");

		}
		return null;
	}

	protected Vector<String> getParents() {
		try {
			Vector<String> myParents = new Vector<String>();
			Vector<Channel> myChannels = new Vector<Channel>();
			myChannels = rom.getAvailableChannels();

			if (!myChannels.isEmpty()) {
				for (int i = 0; i < myChannels.size(); i++) {
					GenericNetworkInterface intf = myChannels.elementAt(i)
							.getConnector().getLocalNetworkInterface();
					boolean isConnectorRole = false;

					if (intf instanceof Bluetooth)
						isConnectorRole = ((Bluetooth) intf).isConnectorRole();
					if (intf instanceof IEEE80211)
						isConnectorRole = ((IEEE80211) intf).isConnectorRole();
					if (!isConnectorRole) {
						String localIP = myChannels.elementAt(i)
								.getChannelLocalIPAddress();
						String[] tokens = localIP.split("\\.");
						String parentIP = tokens[0] + "." + tokens[1] + "."
								+ tokens[2] + ".1";
						myParents.add(parentIP);
					}
				}
			}
			return myParents;
		} catch (Exception e) {
			System.err.println("Impossibile trovare i genitori");
		}
		return null;
	}

	public void run() {

		while (go) {
			try {

				Vector<Channel> myChannels = new Vector<Channel>();
				myChannels = rom.getAvailableChannels();
				if (!myChannels.isEmpty()) {
					for (int i = 0; i < myChannels.size(); i++) {
						GenericNetworkInterface intf = myChannels.elementAt(i)
								.getConnector().getLocalNetworkInterface();
						boolean isConnectorRole = false;
						if (intf instanceof Bluetooth)
							isConnectorRole = ((Bluetooth) intf)
									.isConnectorRole();
						if (intf instanceof IEEE80211)
							isConnectorRole = ((IEEE80211) intf)
									.isConnectorRole();
						if (!isConnectorRole) {
							new ServerSearchFlooding(myChannels.elementAt(i)
									.getChannelLocalIPAddress(), this).start();
						}
					}
				}

				Vector<String> child = new Vector<String>();
				// child.addAll(getChilds());
				child = getChilds();

				if (!child.isEmpty()) {

					Vector<String> localIPchild = localIPChils(child);
					if (!localIPchild.isEmpty()) {

						for (int i = 0; i < localIPchild.size(); i++) {
							new ServerSearchFlooding(localIPchild.elementAt(i),
									this).start();

						}
					}
				}

				sleep(5000);

			} catch (ArrayIndexOutOfBoundsException e) {
				System.err.println("mi sa che c'è sto errore " + e);
			} catch (Exception e) {
				go = false;
				System.err.println("Impossibile lanciare i server folading "
						+ e);
			}
		}

	}

	private Vector<String> localIPChils(Vector<String> child) {
		Vector<String> localIP = new Vector<String>();

		for (int i = 0; i < child.size(); i++) {
			String[] ipvec = child.elementAt(i).split("\\.");

			String ip = ipvec[0] + "." + ipvec[1] + "." + ipvec[2] + ".1";

			if (!vectorContains(localIP, ip))
				localIP.add(ip);

		}

		return localIP;

	}

	public Vector<String> getNeighbourgs() {
		try {
			Vector<String> figli = new Vector<String>();
			Vector<String> padri = new Vector<String>();

			figli = getChilds();
			padri = getParents();
			Vector<String> neighbourg = new Vector<String>();
			// System.err.println("I figli sono:");
			for (int i = 0; i < figli.size(); i++) {
				neighbourg.add(figli.elementAt(i));
				// System.err.println(figli.elementAt(i));
			}
			// System.err.println("I padri sono:");
			for (int i = 0; i < padri.size(); i++) {
				neighbourg.add(padri.elementAt(i));
				// System.err.println(padri.elementAt(i));
			}
			return neighbourg;
		} catch (Exception e) {
			System.err.println("Impossibile trovare i vicini " + e);
		}
		return null;

	}

	// Metodo per vedere se un vettore contiene già una stringa
	private boolean vectorContains(Vector<String> vector, String stringa) {
		for (int i = 0; i < vector.size(); i++) {
			if (vector.elementAt(i).equalsIgnoreCase(stringa))
				return true;
		}
		return false;

	}

	private boolean activeIP(String ip) {
		try {
			String command1 = "ping -s 0 " + ip;
			Process p1 = Runtime.getRuntime().exec(command1);
			BufferedReader stdoutStream1 = new BufferedReader(
					new InputStreamReader(p1.getInputStream()));
			String line;
			int fail = 0;
			int succ = 0;
			while ((line = stdoutStream1.readLine()) != null) {

				if (line.startsWith("From") || line.startsWith("ping")) {
					fail++;
					if (fail > 4) {

						p1.destroy();
						return false;
					}
				}
				if (line.startsWith("8")) {
					succ++;
					if (succ > 2) {
						p1.destroy();
						return true;
					}
				}

			}

			return false;
		} catch (Exception e) {
			System.err
					.println("Impossibile pingare per vedere se l'ip è attivo");
		}
		return false;

	}

	public static void main(String argv[]) throws Exception {
		FindNeighbours vicini = FindNeighbours.getInstance();

		while (true) {
			Vector<String> vic = vicini.getNeighbourgs();
			Vector<String> figlistampa = vicini.getChilds();
			Vector<String> padristampa = vicini.getParents();
			if (figlistampa.size() == 0)
				System.out.println("Nessun figlio");
			else
				for (int i = 0; i < figlistampa.size(); i++) {
					System.out.println("Figlio: " + figlistampa.elementAt(i));
				}
			if (padristampa.size() == 0)
				System.out.println("Nessun padre");
			else
				for (int i = 0; i < padristampa.size(); i++) {
					System.out.println("Padre: " + padristampa.elementAt(i));
				}
			String vicin = "Vicini: ";
			for (int i = 0; i < vic.size(); i++) {
				vicin += vic.elementAt(i) + " ";
			}
			System.out.println(vicin);

			Thread.sleep(5000);

		}

	}

}
